package org.ht.demo.openapi.util;


import org.ht.demo.openapi.annotation.ParseToField;
import org.ht.demo.openapi.annotation.ParseToList;
import org.ht.demo.openapi.annotation.ParseToMethod;

import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 通用数据解析器
 */
public class CommonDataParser {

    /**
     * 16 进数据解析器
     *
     * @param hexString
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T toBean(String hexString, Class<? extends T> clazz) {
        return hexDataPasrer(hexString,clazz);
    }

    public static <E> E hexDataPasrer(String data, Class<? extends E> clazz) {
        E instance = null;
        try {
            instance = clazz.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        /**
         * 解析字段
         */
        Field[] fields = clazz.getDeclaredFields();
        parseField(data, instance, fields);

        /**
         * 解析方法
         */
        Method[] declaredMethods = clazz.getDeclaredMethods();
        parseMethod(data, clazz, instance, declaredMethods);

        /**
         * 解析数组
         */

        try {
            parseList(data,clazz, instance, fields);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }


        return instance;
    }


    private static <T> void parseList(String data,Class<?> clazz, T instance, Field[] fields) throws NoSuchFieldException, IllegalAccessException {
        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];
            if(field.getType() != List.class){
                continue;
            }

            ParseToList listAnnotation = field.getAnnotation(ParseToList.class);
            if(listAnnotation == null){
                continue;
            }

            int byteStart = listAnnotation.byteStart();
            int byteLength = listAnnotation.itemByteLength();
            int listSize = listAnnotation.listSize();
            String sizeFieldName = listAnnotation.listSizeFieldName();

            if(byteLength <= 0){
                continue;
            }

            if(listSize == 0){
                Field sizeField = clazz.getDeclaredField(sizeFieldName);
                sizeField.setAccessible(true);
                Object sizeObj = sizeField.get(instance);
                if(sizeObj == null){
                    continue;
                }
                listSize = (Integer) sizeObj;
                if(listSize == 0){
                    continue;
                }
            }

            Type actualTypeArgument;
            try {
             actualTypeArgument = ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0];
            }catch (ClassCastException e){
                //没有定义泛型,按字符处理;
                actualTypeArgument = String.class;
            }

            if(actualTypeArgument == null){
                continue;
            }

            List list = new ArrayList();
            if(actualTypeArgument == String.class){
                for (int j = 0; j < listSize; j++) {
                    String byteString = getByteStringForList(data, byteStart, byteLength, j);
                    list.add(byteString);
                }
            }else {
                //其他类型递归
                for (int j = 0; j < listSize; j++) {
                    String byteString = getByteStringForList(data, byteStart, byteLength, j);
                    Object listactualObj = hexDataPasrer(byteString, (Class)actualTypeArgument);
                    list.add(listactualObj);
                }
            }
            field.setAccessible(true);
            field.set(instance,list);

        }
    }

    private static <T> void parseMethod(String data, Class<?> clazz, T instance, Method[] declaredMethods) {
        for (int i = 0; i < declaredMethods.length; i++) {
            Method method = declaredMethods[i];
            ParseToMethod methodAnnotation = method.getAnnotation(ParseToMethod.class);
            if(methodAnnotation == null){
                continue;
            }
            int[] byteRange = methodAnnotation.byteRange();
            //没有定义字节区间，跳过
            if (byteRange == null) {
                continue;
            }

            //方法执行的返回字段
            String filedName = methodAnnotation.returnToField();

            try {
                String byteString = null;
                if (byteRange.length == 1) {
                    byteString = DeviceUtils.buileWei(data, byteRange[0], 0);
                } else if (byteRange.length == 2) {
                    byteString = DeviceUtils.buileWei(data, byteRange[0], byteRange[1]);
                }
                Object invokeReturn = method.invoke(instance, byteString);
                //定义了返回字段，就设置value到字段
                if(filedName != null && !filedName.equals("")){
                    Field desField = clazz.getDeclaredField(filedName);
                    desField.setAccessible(true);
                    desField.set(instance,invokeReturn);
                }

            } catch (NoSuchFieldException | IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }

    private static <T> void parseField(String data, T instance, Field[] fields) {
        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];
            if(field.getType() == List.class){
                continue;
            }

            ParseToField fieldAnnotation = field.getAnnotation(ParseToField.class);
            if(fieldAnnotation == null){
                continue;
            }
            int[] byteRange = fieldAnnotation.byteRange();
            if (byteRange == null) {
                continue;
            }

            String byteString = null;
            if (byteRange.length == 1) {
                byteString = DeviceUtils.buileWei(data, byteRange[0], 0);
            } else if (byteRange.length == 2) {
                byteString = DeviceUtils.buileWei(data, byteRange[0], byteRange[1]);
            }
            try {
                field.setAccessible(true);
                if (field.getType() == String.class) {
                    field.set(instance, byteString);
                    continue;
                }
                if (field.getType() == Integer.class) {
                    field.set(instance, Integer.parseInt(byteString, 16));
                    continue;
                }

            } catch (IllegalAccessException e) {

            }

        }
    }

    private static String getByteStringForList(String data, int byteStart, int byteLength, int j) {
        return DeviceUtils.buileWei(data, byteStart + byteLength * j, byteStart + byteLength * (j + 1) - 1);
    }

}
